// RedisGeoController.java
package net.jgrm.product.controller;

import net.jgrm.product.model.GeoLocationInfo;
import net.jgrm.redisadvanced.service.RedisGeoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.domain.geo.Metrics;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * Redis GEO 功能测试控制器
 */
@RestController
@RequestMapping("/geo")
public class RedisGeoController {

    @Autowired
    private RedisGeoService redisGeoService; // 使用String类型作为示例

    /**
     * 添加单个位置信息
     * <p>
     * 示例请求:
     * POST /geo/location?key=shops&member=shop1&longitude=116.404&latitude=39.915
     */
    @PostMapping("/location")
    public Object addLocation(@RequestParam String key,
                              @RequestParam String member,
                              @RequestParam double longitude,
                              @RequestParam double latitude) {
        try {
            Long result = redisGeoService.addLocation(key, member, longitude, latitude);
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("result", result);
            return response;
        } catch (Exception e) {
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("error", e.getMessage());
            return response;
        }
    }

    /**
     * 批量添加位置信息
     * <p>
     * 示例请求:
     * POST /geo/locations?key=shops
     * Body: {"shop1": {"x": 116.404, "y": 39.915}, "shop2": {"x": 121.4737, "y": 31.2304}}
     */
    @PostMapping("/locations")
    public Object addLocations(@RequestParam String key,
                               @RequestBody Map<String, Point> locations) {
        try {
            Long result = redisGeoService.addLocations(key, locations);
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("addedCount", result);
            return response;
        } catch (Exception e) {
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("error", e.getMessage());
            return response;
        }
    }

    /**
     * 获取指定成员的位置信息
     * <p>
     * 示例请求:
     * GET /geo/locations?key=shops&members=shop1,shop2
     */
    @GetMapping("/locations")
    public Object getLocations(@RequestParam String key,
                               @RequestParam List<String> members) {
        try {
            String[] memberArray = members.toArray(new String[0]);
            List<Point> points = redisGeoService.getLocations(key, memberArray);

            Map<String, Point> result = new HashMap<>();
            for (int i = 0; i < members.size() && i < points.size(); i++) {
                result.put(members.get(i), points.get(i));
            }

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("locations", result);
            return response;
        } catch (Exception e) {
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("error", e.getMessage());
            return response;
        }
    }

    /**
     * 计算两个成员之间的距离
     * <p>
     * 示例请求:
     * GET /geo/distance?key=shops&member1=shop1&member2=shop2&unit=KILOMETERS
     */
    @GetMapping("/distance")
    public Object getDistance(@RequestParam String key,
                              @RequestParam String member1,
                              @RequestParam String member2,
                              @RequestParam(defaultValue = "KILOMETERS") String unit) {
        try {
            Metrics metric = Metrics.valueOf(unit.toUpperCase());
            org.springframework.data.geo.Distance distance =
                    redisGeoService.getDistance(key, member1, member2, metric);

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("distance", distance.getValue());
            response.put("unit", distance.getUnit());
            return response;
        } catch (Exception e) {
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("error", e.getMessage());
            return response;
        }
    }

    /**
     * 查找附近的位置（基于坐标点）
     * <p>
     * 示例请求:
     * GET /geo/nearby/point?key=shops&longitude=116.404&latitude=39.915&radius=100&unit=KILOMETERS&count=10
     */
    @GetMapping("/nearby/point")
    public Object getNearbyLocationsByPoint(@RequestParam String key,
                                            @RequestParam double longitude,
                                            @RequestParam double latitude,
                                            @RequestParam double radius,
                                            @RequestParam(defaultValue = "KILOMETERS") String unit,
                                            @RequestParam(defaultValue = "10") long count) {
        try {
            Metrics metric = Metrics.valueOf(unit.toUpperCase());
            //
            GeoResults<RedisGeoCommands.GeoLocation<String>> nearbyLocations = redisGeoService.getNearbyLocations(key, longitude, latitude, radius, metric, count);
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("count", nearbyLocations.getContent().size());
            response.put("results", nearbyLocations.getContent());
            return response;
        } catch (Exception e) {
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("error", e.getMessage());
            return response;
        }
    }

    /**
     * 查找附近的位置（基于已有成员）
     * <p>
     * 示例请求:
     * GET /geo/nearby/member?key=shops&member=shop1&radius=100&unit=KILOMETERS&count=10
     */
    @GetMapping("/nearby/member")
    public Object getNearbyLocationsByMember(@RequestParam String key,
                                             @RequestParam String member,
                                             @RequestParam double radius,
                                             @RequestParam(defaultValue = "KILOMETERS") String unit,
                                             @RequestParam(defaultValue = "10") long count) {
        try {
            Metrics metric = Metrics.valueOf(unit.toUpperCase());
            GeoResults<RedisGeoCommands.GeoLocation<String>> results =
                    redisGeoService.getNearbyLocations(key, member, radius, metric, count);

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("count", results.getContent().size());
            response.put("results", results.getContent());
            return response;
        } catch (Exception e) {
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("error", e.getMessage());
            return response;
        }
    }

    /**
     * 获取附近位置的名称列表
     * <p>
     * 示例请求:
     * GET /geo/nearby/names?key=shops&longitude=116.404&latitude=39.915&radius=100&unit=KILOMETERS
     */
    @GetMapping("/nearby/names")
    public Object getNearbyLocationNames(@RequestParam String key,
                                         @RequestParam double longitude,
                                         @RequestParam double latitude,
                                         @RequestParam double radius,
                                         @RequestParam(defaultValue = "KILOMETERS") String unit) {
        try {
            Metrics metric = Metrics.valueOf(unit.toUpperCase());
            List<String> names = redisGeoService.getNearbyLocationNames(key, longitude, latitude, radius, metric);

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("count", names.size());
            response.put("names", names);
            return response;
        } catch (Exception e) {
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("error", e.getMessage());
            return response;
        }
    }

    /**
     * 删除指定成员
     * <p>
     * 示例请求:
     * DELETE /geo/locations?key=shops&members=shop1,shop2
     */
    @DeleteMapping("/locations")
    public Object removeLocations(@RequestParam String key,
                                  @RequestParam List<String> members) {
        try {
            String[] memberArray = members.toArray(new String[0]);
            Long removedCount = redisGeoService.removeLocations(key, memberArray);

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("removedCount", removedCount);
            return response;
        } catch (Exception e) {
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("error", e.getMessage());
            return response;
        }
    }

    /**
     * 测试完整流程：添加->查询->删除
     * <p>
     * 示例请求:
     * GET /geo/test
     */
    @GetMapping("/test")
    public Object testGeoFlow() {
        try {
            String key = "test_shops";

//            // 1. 添加位置
//            redisGeoService.addLocation(key, "shop1", 116.404, 39.915); // 北京
//            redisGeoService.addLocation(key, "shop2", 121.4737, 31.2304); // 上海
//            redisGeoService.addLocation(key, "shop3", 117.200, 39.100); // 天津
//            redisGeoService.addLocation(key, "shop4", 115.404, 34.915);
//            redisGeoService.addLocation(key, "shop5", 115.4737, 34.2304);
//            redisGeoService.addLocation(key, "shop6", 115.200, 34.100);
//            redisGeoService.addLocation(key, "shop7", 115.410, 34.815);
//            redisGeoService.addLocation(key, "shop8", 115.4837, 34.3304);
//            redisGeoService.addLocation(key, "shop9", 115.210, 34.130);
//            // 2. 查询附近位置 查询附近500公里的位置点
//            GeoResults<RedisGeoCommands.GeoLocation<String>> nearby = redisGeoService.getNearbyLocations(key, 115.404, 34.915, 500, Metrics.KILOMETERS, 10);

            redisGeoService.addLocation(key, "shop1", 116.404, 39.915); // 北京
            redisGeoService.addLocation(key, "shop2", 121.4737, 31.2304); // 上海（距北京约1068公里）
            redisGeoService.addLocation(key, "shop3", 117.200, 39.100); // 天津（距北京约120公里）
            // 修改shop4-shop9的坐标，增加明显距离差异
            redisGeoService.addLocation(key, "shop4", 115.404, 34.915);    // 河南开封
            redisGeoService.addLocation(key, "shop5", 120.1551, 30.2796); // 浙江杭州（距开封约800公里）
            redisGeoService.addLocation(key, "shop6", 113.2644, 23.1291); // 广东广州（距开封约1300公里）
            redisGeoService.addLocation(key, "shop7", 108.9480, 34.2632); // 陕西西安（距开封约500公里）
            redisGeoService.addLocation(key, "shop8", 114.0579, 22.5431); // 深圳（距开封约1400公里）
            redisGeoService.addLocation(key, "shop9", 103.8345, 36.0611); // 甘肃兰州（距开封约1000公里）


            // 2. 查询附近位置 查询附近1500公里的位置点
            GeoResults<RedisGeoCommands.GeoLocation<String>> nearby = redisGeoService.getNearbyLocations(key, 115.404, 34.915, 1500, Metrics.KILOMETERS, 10);

            // 添加详细日志输出
            System.out.println("查询到的附近位置数量: " + nearby.getContent().size());
            nearby.getContent().forEach(result -> {
                String name = result.getContent().getName();
                double distance = result.getDistance().getValue();
                String unit = result.getDistance().getUnit();
                System.out.println("位置: " + name + ", 距离: " + distance + unit);
            });


            // 3. 计算距离
            Distance distance = redisGeoService.getDistance(key, "shop8", "shop9", Metrics.KILOMETERS);

//             4. 删除位置
//            redisGeoService.removeLocations(key, "shop1", "shop2", "shop3");

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);


            response.put("nearby", nearby);
            response.put("nearbyCount", nearby.getContent().size());
            response.put("distance", distance.getValue() + " " + distance.getUnit());
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("error", e.getMessage());
            return response;
        }
    }


    /**
     * 使用对象存储地理位置信息的测试方法 (推荐方式)
     */
    @GetMapping("/test-object-v2")
    public Object testGeoFlowWithObjectV2() {
        try {
            String key = "test_shops_object_v2";

            // 1. 创建地理位置对象列表
            List<GeoLocationInfo> locations = Arrays.asList(
                    new GeoLocationInfo("shop1", "北京店", "北京市中心旗舰店", 116.404, 39.915, "旗舰店"),
                    new GeoLocationInfo("shop2", "上海店", "上海市中心旗舰店", 121.4737, 31.2304, "旗舰店"),
                    new GeoLocationInfo("shop3", "天津店", "天津市中心标准店", 117.200, 39.100, "标准店"),
                    new GeoLocationInfo("shop4", "开封店", "河南开封店", 115.404, 34.915, "标准店"),
                    new GeoLocationInfo("shop5", "杭州店", "浙江杭州店", 120.1551, 30.2796, "标准店"),
                    new GeoLocationInfo("shop6", "广州店", "广东广州店", 113.2644, 23.1291, "标准店"),
                    new GeoLocationInfo("shop7", "西安店", "陕西西安店", 108.9480, 34.2632, "标准店"),
                    new GeoLocationInfo("shop8", "深圳店", "广东深圳店", 114.0579, 22.5431, "标准店"),
                    new GeoLocationInfo("shop9", "兰州店", "甘肃兰州店", 103.8345, 36.0611, "标准店")
            );

            // 2. 使用 JSON 序列化方式存储对象信息 (将对象信息存储在 Hash 中)
            // 2. 批量添加到Redis (现在可以直接使用对象作为member)
            Map<GeoLocationInfo, Point> locationMap = new HashMap<>();
            for (GeoLocationInfo location : locations) {
                Point point = new Point(location.getLongitude(), location.getLatitude());
                locationMap.put(location, point);
            }
            redisGeoService.addLocations(key, locationMap);


            // 2. 查询附近位置 查询附近1500公里的位置点
            GeoResults<RedisGeoCommands.GeoLocation<GeoLocationInfo>> nearby = redisGeoService.getNearbyLocations(key, 115.404, 34.915, 1500, Metrics.KILOMETERS, 10);


            List<Map<String, Object>> processedNearby = new ArrayList<>();
            for (GeoResult<RedisGeoCommands.GeoLocation<GeoLocationInfo>> result : nearby.getContent()) {
                Map<String, Object> locationInfo = new HashMap<>();
                // 位置信息
                RedisGeoCommands.GeoLocation<GeoLocationInfo> location = result.getContent();
                locationInfo.put("name", location);
//                locationInfo.put("longitude", location.getPoint().getX());
//                locationInfo.put("latitude", location.getPoint().getY());

                // 距离信息
                Distance locDistance = result.getDistance();
                Map<String, Object> distanceInfo = new HashMap<>();
                distanceInfo.put("value", locDistance.getValue());
                distanceInfo.put("unit", locDistance.getUnit());
                locationInfo.put("distance", distanceInfo);

                processedNearby.add(locationInfo);
            }


            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("nearby", processedNearby);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("error", e.getMessage());
            return response;
        }
    }

}
